package java_thinking.unit_19._19_11;


import java.util.Random;

/**
 * @Desc:   19.11.1 多路分发
 *      1.要配置好多路分发，需要很多的工序，不过它的好处在于方法调用时优雅的语法，这避免了再一个方法中
 *        判定多个对象的类型的丑陋代码，
 * @author: cww
 * @DateTime: 2019/5/24 18:42
 */
public enum OutCome {
    WIN, LOSE, DRAW
}

/**
 * 多路分发的灵魂所在
 */
interface  Item {
    /**
     * 由 compete 进行分发，根据不同类型分发到相应的 eval()上 第二次分发
     *
     * @param it
     * @return
     */
    OutCome compete(Item it);
    OutCome eval(Paper p);
    OutCome eval(Scissors s);
    OutCome eval(Rock r);
}
class Paper implements Item {
    public OutCome compete(Item it) {
        //将自身作为参数电泳eval() 能够调用重载过的eval()，这能够保留第一次分发的类型信息，当第二次分发
        //完成时，你就能知道两个Item对象的具体类型了
        return it.eval(this);
    }
    public OutCome eval(Paper p) {
        return OutCome.DRAW;
    }
    public OutCome eval(Scissors s) {
        return OutCome.WIN;
    }
    public OutCome eval(Rock r) {
        return OutCome.LOSE;
    }

    @Override
    public String toString() {
        return "Paper";
    }
}

class Scissors implements Item {
    public OutCome compete(Item it) {
        return it.eval(this);
    }
    public OutCome eval(Paper p) {
        return OutCome.LOSE;
    }
    public OutCome eval(Scissors s) {
        return OutCome.DRAW;
    }
    public OutCome eval(Rock r) {
        return OutCome.WIN;
    }

    @Override
    public String toString() {
        return "Scissors";
    }
}

class Rock implements Item {
    public OutCome compete(Item it) {
        return it.eval(this);
    }
    public OutCome eval(Paper p) {
        return OutCome.WIN;
    }
    public OutCome eval(Scissors s) {
        return OutCome.LOSE;
    }
    public OutCome eval(Rock r) {
        return OutCome.DRAW;
    }

    @Override
    public String toString() {
        return "Rock";
    }
}

class RoShamBo1 {
    static final int SIZE = 20;
    private static Random rand = new Random(47);
    public static Item newItem() {
        switch (rand.nextInt(3)) {
            default:
            case 0: return new Scissors();
            case 1: return new Paper();
            case 2: return new Rock();
        }
    }

    /**
     * Item.compete() 会判定a的类型，分发机制会在a的实际类型compete 内部起到分发作用
     * @param a
     * @param b
     */
    public static void match(Item a, Item b) {
        System.out.println(a + " vs " + b + " : " + a.compete(b));
    }

    public static void main(String[] args) {
        for (int i = 0; i < SIZE; i++) {
            match(newItem(), newItem());
        }
    }
}